package com.ztjava.core.tool;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections4.map.HashedMap;
import org.apache.log4j.Logger;
import org.reflections.Reflections;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.jfinal.config.Plugins;
import com.jfinal.config.Routes;
import com.jfinal.plugin.activerecord.DbKit;
import com.jfinal.plugin.activerecord.Model;
import com.xiaoleilu.hutool.io.FileUtil;
import com.xiaoleilu.hutool.util.CharsetUtil;
import com.ztjava.core.annotation.ControllerClass;
import com.ztjava.core.annotation.ModelClass;
import com.ztjava.core.base.BaseController;
import com.ztjava.core.base.BaseSub;
import com.ztjava.core.bean.Database;
import com.ztjava.core.bean.SubBean;
import com.ztjava.core.bean.TableBean;
import com.ztjava.core.client.Client;

public class ScanTool {
	private static Logger logger = Logger.getLogger(ScanTool.class);
	// 配置字段
	private static final String c_sub = "sub";

	private static final String sub_config_name = "config.json";

	/****
	 * 扫描子系统
	 * 
	 * @param config
	 * @return
	 */
	public void scanSub(JSONObject app_config, Map<String, SubBean> subMap,
			Map<String, BaseSub> objectMap) {
		if (app_config == null || app_config.get(c_sub) == null) return;
		JSONObject extConfig = null;
		for (String key : app_config.getJSONObject(c_sub).keySet()) {
			logger.info("开始加载子项目，目标：" + key);
			extConfig = app_config.getJSONObject(c_sub).getJSONObject(key);
			try {
				Reflections reflections = new Reflections(key);
				Set<Class<? extends BaseSub>> projectClassList = reflections.getSubTypesOf(BaseSub.class);
				for (Class<? extends BaseSub> classFile : projectClassList) {
					SubBean subBean = new SubBean();
					String packageName = classFile.getName();
					packageName = packageName.substring(0,packageName.lastIndexOf("."));
					String name = classFile.getName();
					name = name.substring(name.lastIndexOf(".") + 1,name.length());

					subBean.setPackageName(packageName);
					subBean.setName(name);
					subBean.setDb(DbKit.MAIN_CONFIG_NAME);
					subBean.setSkin("");

					// 子系统配置
					if (extConfig.get(name) != null) {
						JSONObject subExtConfig = extConfig.getJSONObject(name);
						if (subExtConfig.get("db") != null)
							subBean.setDb(subExtConfig.getString("db"));
						if (subExtConfig.get("skin") != null)
							subBean.setSkin(subExtConfig.getString("skin"));
					}
					URL fileUrl = classFile.getResource(sub_config_name);
					if(fileUrl!=null){
						try {
							subBean.setConfig(JSONObject.parseObject(FileUtil.readString(fileUrl, CharsetUtil.UTF_8),Feature.OrderedField));
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
					objectMap.put(name, classFile.newInstance());
					subMap.put(name, subBean);
					logger.info(name + "已加载！");
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		logger.info("加载" + subMap.size() + "个子系统");
	}

	/***
	 * 批量加载子系统配置
	 * 初始化时不使用此方法
	 * @param app_config
	 * @return
	 */
	public List<JSONObject> scanSubConfig(JSONObject app_config) {
		List<JSONObject> jsonList = new ArrayList<>();
		if (app_config == null || app_config.get(c_sub) == null)
			return jsonList;
		for (String key : app_config.getJSONObject(c_sub).keySet()) {
			try {
				Reflections reflections = new Reflections(key);
				Set<Class<? extends BaseSub>> projectClassList = reflections
						.getSubTypesOf(BaseSub.class);
				for (Class<? extends BaseSub> classFile : projectClassList) {
					URL fileUrl = classFile.getResource(sub_config_name);
					try {
						JSONObject config = JSONObject.parseObject(FileUtil.readString(fileUrl, CharsetUtil.UTF_8),Feature.OrderedField);
						if (config != null)
							jsonList.add(config);
					} catch (Exception e) {
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return jsonList;
	}

	/***
	 * 扫描Controller
	 * 
	 * @param me
	 * @param subMap
	 * @param app_config
	 */
	public void scanController(Routes me, Map<String, SubBean> subMap,JSONObject app_config) {
		if (app_config == null)return;
		String path = null;
		String actionKey = "";
		Map<String,String> repeatMap = new HashedMap<>();//出现过重复情况
		for (String key : subMap.keySet()) {
			Reflections reflections = new Reflections(subMap.get(key).getPackageName());
			Set<Class<? extends BaseController>> controllerList = reflections.getSubTypesOf(BaseController.class);
			for (Class<? extends BaseController> classFile : controllerList) {
				if (!classFile.isAnnotationPresent(ControllerClass.class)) {
					continue;
				}
				if(repeatMap.containsKey(classFile.getName())){
					logger.info(classFile.getName() +"重复");
					continue;
				}
				Client client;
				try {
					client = (Client) classFile.getAnnotation(ControllerClass.class).client().newInstance();
					path = classFile.getAnnotation(ControllerClass.class).path();
					if (!client.getEnable()) {
						continue;
					}
					actionKey = client.getNamespace() + path;
					if(client.getNamespace().equals("/")){
						actionKey = path;
					}
					logger.info(classFile.getName() + ":"+ actionKey);
					
					if (client.getView() == null) {
						me.add(actionKey, classFile);
					} else {
						if(!subMap.get(key).getSkin().equals("")){
							me.add(actionKey, classFile,client.getView() + "/" + subMap.get(key).getSkin()+ path);
						}else {
							me.add(actionKey, classFile,client.getView() + "/" + client.getSkin()+ path);
						}
					}
					repeatMap.put(classFile.getName(), actionKey);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	/***
	 * 扫描Model
	 * 
	 * @param me
	 * @param subMap
	 * @param dbMap
	 */
	@SuppressWarnings("unchecked")
	public void scanModel(Plugins me, Map<String, SubBean> subMap,Map<String, Database> dbMap) {
		if (dbMap == null || dbMap.size() == 0) return;
		ConfigTool configTool = new ConfigTool();
		MysqlTool mysqlTool = new MysqlTool();
		String tablename = "";
		String db = "";
		try {
			for (String key : subMap.keySet()) {
				db = subMap.get(key).getDb();
				if (!dbMap.containsKey(db)) {
					logger.error("不存在数据源:" + db);
					throw new RuntimeException("不存在数据源:" + db);
				}
				Map<String, TableBean> tableMap = configTool.parseTable(subMap.get(key).getConfig());
				Reflections reflections = new Reflections(subMap.get(key).getPackageName());
				Set<Class<?>> modelList = reflections.getTypesAnnotatedWith(ModelClass.class);
				for (Class<?> classFile : modelList) {
					Class<? extends Model<?>> modelClass = (Class<? extends Model<?>>) classFile;
					tablename = classFile.getAnnotation(ModelClass.class).value();
					//如果没有给表定义，就不会修改表结构
					if (tableMap.containsKey(tablename)) {
						tableMap.get(tablename).setCharacter( classFile.getAnnotation(ModelClass.class).character());
						switch (dbMap.get(db).getType()) {
							case "mysql":
								mysqlTool.bulderTable(dbMap.get(db),tableMap.get(tablename));
								break;
							default:
								break;
						}
					}
					//可以主动设置为空
					String pkey = classFile.getAnnotation(ModelClass.class).primaryKey();
					if(pkey==null||pkey.equals("")){
						dbMap.get(db).getActiveRecordPlugin().addMapping(tablename,modelClass);
					}else {
						dbMap.get(db).getActiveRecordPlugin().addMapping(tablename,pkey, modelClass);
					}
					
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
